﻿namespace MakeVSProject4FFmpeg
{
    #region using directives
    using Mono.Options;
    using System;
    using System.Diagnostics;
    using System.IO;
    #endregion

    /// <summary>
    /// The commandline options.
    /// </summary>
    class CmdLineOptions
    {
        private static readonly string ExeName;

        private string projectName = "vsFFmpeg";

        private string distributionFolder;

        private string outputFolder;

        private string makeFileOutput;

        private bool showHelp;

        private bool parseDependencies;

        private bool enableX64Platform = true;

        private bool enableX86Platform = true;

        private bool enableX264;

        private string libx264Folder;

        private bool enableZlib;

        static CmdLineOptions()
        {
            string fullPath = Process.GetCurrentProcess().ProcessName;
            CmdLineOptions.ExeName = Path.GetFileNameWithoutExtension(fullPath);
        }

        /// <summary>
        /// Gets the name of the project.
        /// </summary>
        /// <value>
        /// The name of the project.
        /// </value>
        public string ProjectName
        {
            get { return this.projectName; }
            private set { this.projectName = value; }
        }

        /// <summary>
        /// Gets the distribution folder - the folder of the FFmpeg-sourcecode.
        /// </summary>
        /// <value>
        /// The distribution folder.
        /// </value>
        public string DistributionFolder
        {
            get { return this.distributionFolder; }
            private set { this.distributionFolder = value; }
        }

        public string OutputFolder
        {
            get { return this.outputFolder; }
            private set { this.outputFolder = value; }
        }

        /// <summary>
        /// Gets the filename with the results from a make.
        /// </summary>
        /// <value>
        /// The filename with the results from a make.
        /// </value>
        public string MakeFileOutput
        {
            get { return this.makeFileOutput; }
            private set { this.makeFileOutput = value; }
        }

        public bool EnableX64Platform
        {
            get { return this.enableX64Platform; }
            private set { this.enableX64Platform = value; }
        }

        public bool EnableX86Platform
        {
            get { return this.enableX86Platform; }
            private set { this.enableX86Platform = value; }
        }

        public bool EnableX264
        {
            get { return this.enableX264; }
            private set { this.enableX264 = value; }
        }

        public bool EnableZLib
        {
            get { return this.enableZlib; }
            private set { this.enableZlib = value; }
        }

        public string LibX264Folder
        {
            get { return this.libx264Folder; }
            private set { this.libx264Folder = value; }
        }

        public string LibZLibFolder
        {
            get { return @"external\zlib"; }
        }

        /// <summary>
        /// Gets a value indicating whether the dependency-files should be parsed.
        /// If not set, the VisualStudio-project will not contain headers.
        /// </summary>
        /// <value>
        /// <c>True</c> if dependency-files shoudl be parsed; otherwise, <c>false</c>.
        /// </value>
        public bool ParseDependencies
        {
            get { return this.parseDependencies; }
            private set { this.parseDependencies = value; }
        }

        public string GetDistributionFolderOrCurrentDir()
        {
            if (!string.IsNullOrWhiteSpace(this.DistributionFolder))
            {
                return this.DistributionFolder;
            }

            return Directory.GetCurrentDirectory();
        }

        public bool ParseCmdLine(string[] args)
        {
            OptionSet optionSet = this.CreateCommandLineParser();
            try
            {
                optionSet.Parse(args);

                if (!this.showHelp)
                {
                    if (string.IsNullOrWhiteSpace(this.MakeFileOutput))
                    {
                        throw new OptionException("Filename of the make-output must be specified.", "-m");
                    }

                    if (this.ParseDependencies && string.IsNullOrWhiteSpace(this.DistributionFolder))
                    {
                        string fullPath = Path.GetFullPath(this.MakeFileOutput);
                        string distribFolder = Path.GetDirectoryName(fullPath);
                        if (!DoesFolderExists(distribFolder))
                        {
                            throw new OptionException("Distribution-folder does not exist.", "-d");
                        }

                        this.DistributionFolder = distribFolder;
                    }

                    if (this.EnableX264)
                    {
                        this.LibX264Folder = @"external\x264";
                    }
                }
            }
            catch (OptionException e)
            {
                Console.Write("{0}: ", ExeName);
                Console.WriteLine(e.Message);
                Console.WriteLine("Try `{0} --help' for more information.", ExeName);
                return false;
            }

            if (this.showHelp)
            {
                ShowHelp(optionSet);
                return false;
            }

            return true;
        }

        private static bool DoesFolderExists(string folderName)
        {
            return Directory.Exists(folderName);
        }

        private static void ShowHelp(OptionSet p)
        {
            Console.WriteLine("Usage: {0} [options]+", ExeName);
            Console.WriteLine();
            Console.WriteLine("This program creates a VisualStudio-project for building FFmpeg with the");
            Console.WriteLine("VisualStudio-IDE. You need to specify the output from a dry-run of 'make'");
            Console.WriteLine("which has been saved to a file (e.g. 'make --dry-run > makelog.txt').");
            Console.WriteLine("Optionally it also parses the dependency-files so that the header-files are");
            Console.WriteLine("also included in the VisualStudio-project.");
            Console.WriteLine();
            Console.WriteLine("Options:");
            p.WriteOptionDescriptions(Console.Out);
        }

        private OptionSet CreateCommandLineParser()
        {
            return new OptionSet()
                        {
                            {
                                "p|projname=", 
                                "The name of the VisualStudio-project [default: vsFFmpeg]",
                                v => this.ProjectName = v
                            },
                            {
                                "d|distdir=",
                                "The folder where the FFmpeg-distribution is located. Only used if the 'parse_includes'-option is used. [default: folder where the makefile-output is located]",
                                v =>
                                    {
                                        if (!DoesFolderExists(v))
                                        {
                                            throw new OptionException(
                                                string.Format("Distribution-folder \"{0}\" does not exists.",v),
                                                "-d");
                                        }

                                        this.DistributionFolder = v;
                                    }
                            },
                            {
                                "o|outputdir=",
                                "The folder where the VisualStudio-projects are to be written to [default: current directory].",
                                v =>
                                    {
                                        if (!DoesFolderExists(v))
                                        {
                                            throw new OptionException(
                                                string.Format("Output-folder \"{0}\" does not exists.",v),
                                                "-o");
                                        }

                                        this.OutputFolder = v;
                                    }
                            },
                            {
                                "m|makefileoutput=",
                                "Filename of makefile-output. This argument is mandatory.",
                                v =>
                                    {
                                        this.MakeFileOutput = v;
                                    }
                            },
                            {
                              "i|parse_includes",
                              "Also include headers in the VS-project by parsing the .d-files.",
                               v => this.ParseDependencies = v != null 
                            },
                            {
                              "8|x86platform",
                              "Include the x86-platform in the solution [default=on].",
                               v => this.EnableX86Platform = v != null 
                            },
                            {
                              "6|x64platform",
                              "Include the x64-platform in the solution [default=on].",
                               v => this.EnableX64Platform = v != null 
                            },
                            {
                                "libx264",
                                "Include the x264-library in the solution.",
                                v => this.EnableX264 = v != null
                            },
                            {
                                "libzlib",
                                "Include the zlib-library in the solution.",
                                v => this.EnableZLib = v != null
                            },
                            { 
                                "h|help",  
                                "show this message and exit", 
                                v => this.showHelp = v != null 
                            }
                        };
        }
    }
}
